#include "netdisk.h"

// 实现文件下载功能
// 检查指定路径 arg 是否存在于当前目录
int isInThisList(char *arg){
    DIR* drip=opendir(arg); // 打开当前目录（.）并逐个读取目录项
    struct dirent* dire;
    dire=readdir(drip);
    while(dire!=NULL){
        // 如果目录项的名称与 arg 相同，返回 1，表示存在
        if(strcmp(dire->d_name,arg)==0){
            return 1;
        }
        dire=readdir(drip);
    }
    closedir(drip);
    return 0;
}

// 从完整路径中提取文件名 e.g. //path/to/file.txt -> file.txt
void cutstr(char * input,char *filename){
    //char filename[256]; // 假定文件名不超过256个字符

    char *filename_start = strrchr(input, '/');
    if (filename_start != NULL) { // 如果发现'/'，则文件名为'/'之后的内容
        filename_start++; // 跳过'/'，指向文件名的起始位置
    } else {
        filename_start = input; // 否则整个字符串都是文件名
    }

    strcpy(filename, filename_start); // 复制文件名到新的字符数组中
   // printf("%s\n",filename);
    //return filename;
}

// 从服务器下载文件
// const char *arg：文件路径或文件名
int getsTextFunc(const char* arg,int netfd, Stack_t dir){//输入差一个栈参数，后面可以补上
    //char* ptext = cutstr(arg);
    //char ptext[256];
    //cutstr(arg,ptext);//ptext为要传输的文件的文件名
    //int num = strlen(ptext);
    
    // train_name_t train;
    
    //train.length=num;
    //strcpy(train.data,ptext);
    //send(netfd,&train,sizeof(train.length),MSG_NOSIGNAL);
    //send(netfd,&train.data,train.length,MSG_NOSIGNAL);
    
    // 将用户输入的路径arg，转换为绝对路径（因为用户操作的只是虚拟路径） 
    char real_path[4096] = {0};
    onePath(arg, real_path, &dir);
    
    // recvn(netfd,&train.length,sizeof(train.length));//接收文件名火车头
    // recvn(netfd,&train.offset,sizeof(train.offset));
    // recvn(netfd,train.data,train.length);//接收文件火车箱

    // 接收客户端的文件偏移量，即先判断客户端接收了多少数据，用于断点续传
    // 从套接字中接收文件的偏移量offset,用于断点续传，从上次中断的位置开始接收文件
    off_t offset = 0;
    recvn(netfd, &offset, sizeof(off_t));
    
    int fd = open(real_path, O_RDWR);//open第一个参数为绝对地址
    // 文件打开失败的处理
    if(fd==-1){
        tran_t errorMsg;
        bzero(&errorMsg, sizeof(tran_t));
        strcmp(errorMsg.data, "file not exist\n");
        errorMsg.length = strlen(errorMsg.data);
        
        send(netfd, &fd, sizeof(int),MSG_NOSIGNAL);
        send(netfd, &errorMsg, sizeof(int) + errorMsg.length, MSG_NOSIGNAL);
        return -1;//返回错误类型为未打开文件
    }else{
        // 服务器成功打开要发送的文件，则向客户端发送标识符
        int ret = 0;
        send(netfd, &ret, sizeof(int), MSG_NOSIGNAL);
    }

    // 获取文件的状态信息，将其存储在statbuf中
    struct stat statbuf;
    fstat(fd,&statbuf);
    //train.length=sizeof(statbuf.st_size);
    //memcpy(train.data,&statbuf.st_size,train.length);
    //send(netfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
    
    tran_t train;
    bzero(&train, sizeof(train));

    // 内存映射传输（大文件）
    if(statbuf.st_size > 1000000)
	{
        // 若文件大小超过1MB，使用mmap将文件映射道内存中
        //int offset = train.offset;
		char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
		ERROR_CHECK(p,MAP_FAILED,"mmap");
		off_t totalsize = offset; // 从偏移量offset开始，逐块发送文件内容
        while(totalsize < statbuf.st_size) // 判断文件没有发送完全时
		{
			// 若是剩下文件大小大于4096，则每次发送数据块大小为4096
            if(statbuf.st_size - totalsize > (off_t)sizeof(train.data))
				train.length = 4096;
			else
                // 若是剩余内容小于4096，则把剩余内容一块发送了
				train.length = statbuf.st_size - totalsize;
            // 小火车协议，依次发送文件的大小以及文件内容
			send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
            // send(netfd,&train.offset,sizeof(train.offset),MSG_NOSIGNAL);
			send(netfd,p+totalsize,train.length,MSG_NOSIGNAL);
			totalsize += train.length;
		}
	}
    // 内存银蛇传输（发送小文件）
	else
    {
        // 如果文件大小小于1MB，则使用lseek定位道偏移量offset
    lseek(fd, offset,SEEK_SET);
    int text_num=0;
        while(1){
            // 逐块读取文件内容
            ssize_t sret=read(fd,train.data,sizeof(train.data));
            if(sret==0){
                break;
            }
            train.length = sret;
            // send(netfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
            sret = send(netfd, &train, sizeof(int)+train.length,MSG_NOSIGNAL);
        }
    }
    printf("all send over\n");
    // 文件发送结束后，发送一个长度为0的数据块，作为文件传输结束的标志
    train.length=0;
    send(netfd,&train,sizeof(train.length),MSG_NOSIGNAL);
    return 0;
}


